//
// Created by v on 24-10-28.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "geminai_wind_protocol_wrap.h"
#include "cJSON.h"
#include "cm_common.h"
#include "cm_base64.h"
#include "freertos/FreeRTOS.h"
#include "geminai_modbus.h"
#include "geminai_modbus_master.h"
#include "driver/gpio.h"

#include <sys/stat.h>
#include <errno.h>
#include "esp_system.h"
#include "geminai_log.h"
#include "display_photo_event.h"

#include "system_event_list.h"
extern void swapBytes(uint16_t *array, size_t size);
static const char *TAG = "geminai_wind_protocol_wrap";
static uint32_t s_seq_num = 0;

EXT_RAM_BSS_ATTR char image_buffer[800 * 1024];

static uint32_t getSeq()
{
    if (s_seq_num >= INT32_MAX)
    {
        s_seq_num = 1;
    }
    return s_seq_num++;
}

int wind_protocol_wrap_up_parse_header(char *data, int len, WindProUpdateHeader *header)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "timestamp");
        if (obj)
        {
            header->timestamp = (uint64_t)cJSON_GetNumberValue(obj);
        }
        obj = cJSON_GetObjectItem(root, "seqNum");
        if (obj)
        {
            header->seqNum = (uint32_t)cJSON_GetNumberValue(obj);
        }
        obj = cJSON_GetObjectItem(root, "cmdType");
        if (obj)
        {
            header->cmdType = (uint32_t)cJSON_GetNumberValue(obj);
        }
        cJSON_Delete(root);
        return 0;
    }
    else
    {
        cJSON_Delete(root);
        return -2;
    }
    return -1;
}

int wind_protocol_wrap_up_parse_response_version(char *data, int len, WindProUpdateVersion *version)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "result");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "version");
            if (obj_sub)
            {
                strncpy(version->version, cJSON_GetStringValue(obj_sub), sizeof(version->version));
                cJSON_Delete(root);
                return 0;
            }
        }
    }
    cJSON_Delete(root);
    LOGD("Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_gen_request_version(char *data, int len)
{
    cJSON *root = cJSON_CreateObject();
    uint32_t seq = getSeq();
    cJSON_AddNumberToObject(root, "timestamp", seq);
    cJSON_AddNumberToObject(root, "seqNum", seq);
    cJSON_AddNumberToObject(root, "cmdType", WIND_PRO_UP_CMD_VERSION);
    cJSON_AddStringToObject(root, "info", "");
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_response_version(char *data, int len, WindProUpdateHeader *header, char *version)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "timestamp", header->timestamp);
    cJSON_AddNumberToObject(root, "seqNum", header->seqNum);
    cJSON_AddNumberToObject(root, "cmdType", header->cmdType);
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddStringToObject(obj, "version", version);
    cJSON_AddItemToObject(root, "result", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_request_query_system(char *data, int len)
{
    cJSON *root = cJSON_CreateObject();
    uint32_t seq = getSeq();
    cJSON_AddNumberToObject(root, "timestamp", seq);
    cJSON_AddNumberToObject(root, "seqNum", seq);
    cJSON_AddNumberToObject(root, "cmdType", WIND_PRO_UP_CMD_QUERY_SYSTEM);
    cJSON_AddStringToObject(root, "info", "");
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_response_query_system(char *data, int len, WindProUpdateSystemInfo *info)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "timestamp", info->header.timestamp);
    cJSON_AddNumberToObject(root, "seqNum", info->header.seqNum);
    cJSON_AddNumberToObject(root, "cmdType", info->header.cmdType);
    cJSON *obj = cJSON_CreateObject();
    if (info->header.result == 0)
    {
        cJSON_AddNumberToObject(obj, "cmd", info->cmd);
        cJSON_AddNumberToObject(obj, "open_count", info->open_count);
        cJSON_AddNumberToObject(obj, "angle", info->angle);
    }
    cJSON_AddNumberToObject(obj, "error", info->header.result);

    cJSON_AddItemToObject(root, "result", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_parse_response_query_system(char *data, int len, WindProUpdateSystemInfo *info)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "result");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "error");
            if (obj_sub)
            {
                info->header.result = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "cmd");
            if (obj_sub)
            {
                info->cmd = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "open_count");
            if (obj_sub)
            {
                info->open_count = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "angle");
            if (obj_sub)
            {
                info->angle = cJSON_GetNumberValue(obj_sub);
            }

            cJSON_Delete(root);
            return 0;
        }
    }
    cJSON_Delete(root);
    LOGD("Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_gen_request_query_config(char *data, int len)
{
    cJSON *root = cJSON_CreateObject();
    uint32_t seq = getSeq();
    cJSON_AddNumberToObject(root, "timestamp", seq);
    cJSON_AddNumberToObject(root, "seqNum", seq);
    cJSON_AddNumberToObject(root, "cmdType", WIND_PRO_UP_CMD_QUERY_CONFIG);
    cJSON_AddStringToObject(root, "info", "");
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_response_query_config(char *data, int len, WindProUpdateConfig *config)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "timestamp", config->header.timestamp);
    cJSON_AddNumberToObject(root, "seqNum", config->header.seqNum);
    cJSON_AddNumberToObject(root, "cmdType", config->header.cmdType);
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "door_open_angle", config->door_open_angle);
    cJSON_AddNumberToObject(obj, "capture_angle", config->capture_angle);
    cJSON_AddNumberToObject(obj, "door_open_timeout", config->door_open_timeout);

    cJSON_AddItemToObject(root, "result", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_parse_response_query_config(char *data, int len, WindProUpdateConfig *config)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "result");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "door_open_angle");
            if (obj_sub)
            {
                config->door_open_angle = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "capture_angle");
            if (obj_sub)
            {
                config->capture_angle = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "door_open_timeout");
            if (obj_sub)
            {
                config->door_open_timeout = cJSON_GetNumberValue(obj_sub);
            }
            cJSON_Delete(root);
            return 0;
        }
    }
    cJSON_Delete(root);
    LOGD("Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_gen_request_set_config(char *data, int len, WindProUpdateConfig *config)
{
    cJSON *root = cJSON_CreateObject();
    uint32_t seq = getSeq();
    cJSON_AddNumberToObject(root, "timestamp", seq);
    cJSON_AddNumberToObject(root, "seqNum", seq);
    cJSON_AddNumberToObject(root, "cmdType", WIND_PRO_UP_CMD_SET_CONFIG);

    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "door_open_angle", config->door_open_angle);
    cJSON_AddNumberToObject(obj, "capture_angle", config->capture_angle);
    cJSON_AddNumberToObject(obj, "door_open_timeout", config->door_open_timeout);

    cJSON_AddItemToObject(root, "info", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_response_set_config(char *data, int len, WindProUpdateConfig *config, int result)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "timestamp", config->header.timestamp);
    cJSON_AddNumberToObject(root, "seqNum", config->header.seqNum);
    cJSON_AddNumberToObject(root, "cmdType", config->header.cmdType);
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "error", result);

    cJSON_AddItemToObject(root, "result", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_parse_response_set_config(char *data, int len)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "result");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "error");
            if (obj_sub)
            {
                int err = cJSON_GetNumberValue(obj_sub);
                return err == 0 ? 0 : -3;
            }
            cJSON_Delete(root);
            return -2;
        }
    }
    cJSON_Delete(root);
    LOGD("Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_parse_request_set_config(char *data, int len, WindProUpdateConfig *config)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "info");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "door_open_angle");
            if (obj_sub)
            {
                config->door_open_angle = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "capture_angle");
            if (obj_sub)
            {
                config->capture_angle = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "door_open_timeout");
            if (obj_sub)
            {
                config->door_open_timeout = cJSON_GetNumberValue(obj_sub);
            }
            cJSON_Delete(root);
            return 0;
        }
    }
    cJSON_Delete(root);
    LOGD("Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_gen_request_usb_stream(char *data, int len, int open)
{
    cJSON *root = cJSON_CreateObject();
    uint32_t seq = getSeq();
    cJSON_AddNumberToObject(root, "timestamp", seq);
    cJSON_AddNumberToObject(root, "seqNum", seq);
    cJSON_AddNumberToObject(root, "cmdType", open == 1 ? WIND_PRO_UP_CMD_OPEN_USB_STREAM : WIND_PRO_UP_CMD_CLOSE_USB_STREAM);

    cJSON_AddStringToObject(root, "info", "");
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_response_usb_stream(char *data, int len, int result, WindProUpdateHeader *header)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "timestamp", header->timestamp);
    cJSON_AddNumberToObject(root, "seqNum", header->seqNum);
    cJSON_AddNumberToObject(root, "cmdType", header->cmdType);
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "error", result);

    cJSON_AddItemToObject(root, "result", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_parse_response_usb_stream(char *data, int len)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "result");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "error");
            if (obj_sub)
            {
                int err = cJSON_GetNumberValue(obj_sub);
                return err == 0 ? 0 : -3;
            }
            cJSON_Delete(root);
            return -2;
        }
    }
    cJSON_Delete(root);
    LOGD("Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_gen_request_photo(char *data, int len, WindProUpdateQueryPhoto *photo)
{
    cJSON *root = cJSON_CreateObject();
    uint32_t seq = getSeq();
    cJSON_AddNumberToObject(root, "timestamp", seq);
    cJSON_AddNumberToObject(root, "seqNum", seq);
    cJSON_AddNumberToObject(root, "cmdType", WIND_PRO_UP_CMD_QUERY_PHOTO);

    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "open_count", photo->open_count);
    cJSON_AddNumberToObject(obj, "angle", photo->angle);
    cJSON_AddNumberToObject(obj, "offset", photo->offset);
    cJSON_AddNumberToObject(obj, "length", photo->length);

    cJSON_AddItemToObject(root, "info", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_gen_response_photo(char *data, int len, WindProUpdateQueryPhoto *photo)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "timestamp", photo->header.timestamp);
    cJSON_AddNumberToObject(root, "seqNum", photo->header.seqNum);
    cJSON_AddNumberToObject(root, "cmdType", photo->header.cmdType);
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddNumberToObject(obj, "error", photo->header.result);
    cJSON_AddNumberToObject(obj, "size", photo->size);
    cJSON_AddNumberToObject(obj, "length", photo->data_len);
    // save data
    char outdata[512] = {0};
    size_t d_str_len = photo->data_len;
    cm_base64_encode((unsigned char *)outdata, &d_str_len, photo->data, photo->data_len);
    cJSON_AddStringToObject(obj, "data", outdata);

    cJSON_AddItemToObject(root, "result", obj);
    char *d = cJSON_PrintUnformatted(root);
    strncpy(data, d, strlen(d) > len ? len : strlen(d));
    cJSON_free(d);
    cJSON_Delete(root);
    return strlen(data);
}

int wind_protocol_wrap_up_parse_response_photo(char *data, int len, WindProUpdateQueryPhoto *photo, WindProUpdateSystemInfo *info)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        /*add : ===获取系统事件===*/
        memset(info, 0, sizeof(WindProUpdateSystemInfo));
        cJSON *obj_sub = cJSON_GetObjectItem(root, "system_event");
        if (obj_sub)
        {
            cJSON *obj = cJSON_GetObjectItem(obj_sub, "error");
            if (obj)
            {
                info->header.result = cJSON_GetNumberValue(obj);
            }
            obj = cJSON_GetObjectItem(obj_sub, "cmd");
            if (obj)
            {
                info->cmd = cJSON_GetNumberValue(obj);
            }
            obj = cJSON_GetObjectItem(obj_sub, "open_count");
            if (obj)
            {
                info->open_count = cJSON_GetNumberValue(obj);
            }
            obj = cJSON_GetObjectItem(obj_sub, "angle");
            if (obj)
            {
                info->angle = cJSON_GetNumberValue(obj);
            }
        }
        /*add : ===获取系统事件===*/

        cJSON *obj = cJSON_GetObjectItem(root, "result");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "error");
            if (obj_sub)
            {
                int err = cJSON_GetNumberValue(obj_sub);
                photo->header.result = err;
            }
            obj_sub = cJSON_GetObjectItem(obj, "size");
            if (obj_sub)
            {
                photo->size = cJSON_GetNumberValue(obj_sub);
                printf("parse photo size [%lld]\n", photo->size);
            }
            obj_sub = cJSON_GetObjectItem(obj, "length");
            if (obj_sub)
            {
                photo->data_len = cJSON_GetNumberValue(obj_sub);
            }

            obj_sub = cJSON_GetObjectItem(obj, "data");
            if (obj_sub)
            {
                char *str = cJSON_GetStringValue(obj_sub);
                size_t d_str_len = 7000;
                // cm_base64_decode((unsigned char *)photo->data_p, &d_str_len, (unsigned char *)str, photo->data_len);
                int ret = cm_base64_decode((unsigned char *)photo->data_p, &d_str_len, (unsigned char *)str, photo->data_len);

                // 打印解码后的信息
                if (ret == 0)
                {
                    printf("parsr photo data Base64 decode successful. Decoded length: %zu\n", d_str_len);
                }
                else
                {
                    printf("Base64 decode failed with error code: %d\n", ret);
                }
                printf("parse photo data    data len [%d] decode len [%d]\n", photo->data_len, d_str_len);
                photo->data_len = d_str_len;
            }
            cJSON_Delete(root);
            return -2;
        }
    }
    cJSON_Delete(root);
    GEMINAI_LOGD(TAG, "Error [%s]\n", data);
    return -1;
}

int wind_protocol_wrap_up_parse_request_photo(char *data, int len, WindProUpdateQueryPhoto *photo)
{
    cJSON *root = cJSON_ParseWithLength(data, len);
    if (root)
    {
        cJSON *obj = cJSON_GetObjectItem(root, "info");
        if (obj)
        {
            cJSON *obj_sub = cJSON_GetObjectItem(obj, "open_count");
            if (obj_sub)
            {
                photo->open_count = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "length");
            if (obj_sub)
            {
                photo->length = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "angle");
            if (obj_sub)
            {
                photo->angle = cJSON_GetNumberValue(obj_sub);
            }
            obj_sub = cJSON_GetObjectItem(obj, "offset");
            if (obj_sub)
            {
                photo->offset = cJSON_GetNumberValue(obj_sub);
            }
            cJSON_Delete(root);
            return -2;
        }
    }
    cJSON_Delete(root);
    GEMINAI_LOGE(TAG, "Error [%s]\n", data);
    return -1;
}

static void defcommnd_up(char *buf, int len, char *result, int len_result)
{
    mb_param_request_t *request = (mb_param_request_t *)malloc(sizeof(mb_param_request_t));
    if (request == NULL)
    {
        GEMINAI_LOGE(TAG, "Failed to allocate memory for request\n");
        return;
    }
    request->slave_addr = MB_DEVICE_ADDRESS;
    request->command = 0x17;
    request->write_regstart = 0;
    request->write_regsize = 256;
    request->reg_start = 0;
    request->reg_size = 8000 / 2;

    char *rev = malloc(8000);
    if (rev == NULL)
    {
        ESP_LOGE(TAG, "defcommnd_up Memory allocation failed for read buffer."); // 打印内存分配失败信息
    }
    else
    {
        ESP_LOGI(TAG, "defcommnd_up Memory allocated successfully for read buffer: %zu bytes", 8000); // 打印分配的内存大小
    }
    request->readbuf = rev;

    char version_len = len;
    uint16_t version_cmd[128] = {0};
    version_cmd[0] = 0xFCFD;
    version_cmd[1] = 0xFAFB;
    version_cmd[2] = 0x0064;
    memcpy(version_cmd + 3, &version_len, 1);
    memcpy(version_cmd + 4, buf, version_len);

    request->write_regsize = (8 + version_len) / 2 + 1;
    swapBytes(&version_cmd, 128);
    //    for(int i = 0;i<128;i++)
    //    {
    //        printf("0x%2x\t",version_cmd[i]);
    //    }
    esp_err_t err = mbc_master_send_request(request, version_cmd);
    if (err != ESP_OK)
    {
        GEMINAI_LOGE(TAG, "master send request failed [%x]\n", err);
        return;
    }

    printf(TAG, "transfer complete err [%d]\n", err);

    printf("\n");
    uint16_t cmd_len = 0;
    swapBytes((uint16_t *)rev, 8000 / 2);
    memcpy(&cmd_len, rev, 2);
    printf(TAG, "recv data len:%d\n", cmd_len);
    for (int i = cmd_len - 30; i < cmd_len - 1; i++)
    {
        printf("%02x ", rev[i]);
    }
    printf("\n");
    if (cmd_len == 0)
    {
        free(rev);
        free(request);
        return;
    }

    if (cmd_len > 8000)
    {
        GEMINAI_LOGE(TAG, "error len [%d]\n", cmd_len);
    }
    else
    {
        memcpy(result, rev + 2, cmd_len);
    }
    free(rev);
    free(request);
}
void wind_get_software()
{
    GEMINAI_LOGI(TAG, "wind get software");
    char buf[512] = {0};
    int len = sizeof(buf);
    wind_protocol_wrap_up_gen_request_version(buf, len);
    GEMINAI_LOGI(TAG, "data len [%d] date buf [%s]", strlen(buf), buf);
    char result[512] = {0};
    int len_result = sizeof(result);
    defcommnd_up(buf, strlen(buf), result, len_result);
    printf("result: [%s]\n", result);
}

static void add_system_event_to_link_list(WindProUpdateSystemInfo *systemInfo)
{
    if (systemInfo->cmd == 1)
    {
        wind_system_event_push(1, systemInfo->open_count, systemInfo->angle);
    }
    else if (systemInfo->cmd == 2)
    {
        wind_system_event_push(2, systemInfo->open_count, systemInfo->angle);
    }
}

static void printf_system_event(WindProUpdateSystemInfo *systemInfo)
{

    if (systemInfo->cmd == 1)
    {
        printf("********** System Event **********\n");
        printf("  [system event] : %s\n", "Door Open");
        printf("  [Open Count]: %u\n", systemInfo->open_count);
        printf("  [Angle]: %f\n", systemInfo->angle);
        // 输出结束标识
        printf("***********************************\n");
    }
    else if (systemInfo->cmd == 2)
    {
        printf("********** System Event **********\n");
        printf("  [system event] : %s\n", "Door close");
        printf("  [Open Count]: %u\n", systemInfo->open_count);
        printf("  [Angle]: %f\n", systemInfo->angle);
        // 输出结束标识
        printf("***********************************\n");
    }
}

static void printf_request_photot_result(int result)
{
    switch (result)
    {
    case 1:
        GEMINAI_LOGI(TAG, "image not exist"); /*图片不存在，可能t23开门了但是没达到拍照角度*/
        break;
    }
}
#include "geminai_vision_1106.h"
static void door_event_handler(WindProUpdateSystemInfo *systemInfo)
{
    /*开门事件*/
    if (systemInfo->cmd == 1)
    {
        door_event_report("opened_door_event", systemInfo->angle, systemInfo->open_count);
    }
    /*关门事件*/
    else if (systemInfo->cmd == 2)
    {
        door_event_report("closed_door_event", systemInfo->angle, systemInfo->open_count);
    }
}


void wind_get_event()
{
    GEMINAI_LOGI(TAG, "Query system event");
    char buf[512] = {0};
    int len = sizeof(buf);
    WindSystemEvent *event;
    WindProUpdateSystemInfo systemInfo;
    WindProUpdateQueryPhoto photo;
    memset(&photo, 0, sizeof(photo));
    memset(&systemInfo, 0, sizeof(systemInfo));
    char result[8000] = {0};
    int len_result = sizeof(result);

    /*处理完存储在本地的事件，才会向t23发送系统事件查询*/
    int event_source_flag = 0;

    /*查询本地是否有系统事件*/
    event = wind_system_event_pop();
    if (event != NULL)
    {
         event_source_flag = 0;
        /*说明有本地事件链表中有待处理的系统事件*/
        printf("get systerm event from link list\n");
        systemInfo = event->info;
    }
    else
    {
        event_source_flag = 1;
        /*本地没有，则向摄像头发送系统事件查询请求*/
        printf("start send systerm event qurey reuqest to camera\n");
        /*构建系统事件请求包*/
        wind_protocol_wrap_up_gen_request_query_system(buf, len);
        printf("data len [%d]  data buf [%s]\n", strlen(buf), buf);
        /*发送并接收*/
        defcommnd_up(buf, strlen(buf), result, len_result);
        printf("get event result form cam: [%s]\n", result);
        /*解析接收到的结果*/
        wind_protocol_wrap_up_parse_response_query_system(result, len_result, &systemInfo);
    }

    if (systemInfo.cmd == 1)
    {
        if (event_source_flag == 1)
        {
            /*该事件是从t23处最新请求得到的*/
            /*上报开门事件*/
            door_event_report("opened_door_event", systemInfo.angle, systemInfo.open_count);
        }
        printf_system_event(&systemInfo);
        return;
    }
    else if (systemInfo.cmd == 2)
    {
        if (event_source_flag == 1)
        {
            /*该事件是从t23处最新请求得到的*/
            /*上报关门事件*/
            door_event_report("closed_door_event", systemInfo.angle, systemInfo.open_count);
        }
        vTaskDelay(200);
        printf_system_event(&systemInfo);
        GEMINAI_LOGI(TAG, "start get photo");
        uint64_t img_size = 9999;
        uint64_t img_read = 0;
        WindProUpdateSystemInfo trans_ing_sys_info;
        while (img_read < img_size)
        {
            photo.open_count = systemInfo.open_count;
            photo.angle = systemInfo.angle;
            photo.length = 5000;
            photo.offset = img_read;
            photo.data_p = (uint8_t *)malloc(7000);
            if (photo.data_p == NULL)
            {
                ESP_LOGE(TAG, "Memory allocation failed for photo.data_p."); // 打印内存分配失败信息
            }
            char req_data[512] = {0};
            int req_len = sizeof(req_data);
            memset(&result, 0, sizeof(result));
            wind_protocol_wrap_up_gen_request_photo(req_data, req_len, &photo);
            printf("get photo request [%s]\n", req_data);
            defcommnd_up(req_data, strlen(req_data), result, len_result);
            wind_protocol_wrap_up_parse_header(result, len_result, &photo.header);
            wind_protocol_wrap_up_parse_response_photo(result, len_result, &photo, &trans_ing_sys_info);

            /* 打印获取到的事件 */
            printf_system_event(&trans_ing_sys_info);

            /*添加获取到的系统事件到本地链表存储*/
            add_system_event_to_link_list(&trans_ing_sys_info);

            /* 处理开关门事件 */
            door_event_handler(&trans_ing_sys_info);

            if (photo.header.result != 0)
            {
                printf_request_photot_result(photo.header.result);
                free(photo.data_p);
                return;
            }
            if (img_size == 9999)
            {
                GEMINAI_LOGI(TAG, "total image size [%llu]", photo.size);
                img_size = photo.size;
            }
            img_read += photo.data_len;
            printf("read out data [%llu]", img_read);

            /*   拷贝到ram空间  */
            memcpy(image_buffer + photo.offset, photo.data_p, photo.data_len);

            if (photo.data_len <= 8)
            {
                for (int i = 0; i < photo.data_len; i++)
                {
                    printf("%02x ", photo.data[i]);
                }
            }
            else
            {
                printf("[%02x %02x %02x %02x] [%02x %02x %02x %02x]\n", photo.data_p[0], photo.data_p[1], photo.data_p[2],
                       photo.data_p[3], photo.data_p[photo.data_len - 4], photo.data_p[photo.data_len - 3], photo.data_p[photo.data_len - 2],
                       photo.data_p[photo.data_len - 1]);
            }
            free(photo.data_p);
            printf("\n");
            vTaskDelay(20);
        }
        send_disp_photo_event(photo.angle);
        upload_oss(image_buffer, img_read);
    }
    else
    {
        printf("[sysytem event] : no event\n");
    }
}

void wind_get_config()
{
    GEMINAI_LOGI(TAG, "wind get config\n");
    char buf[512] = {0};
    int len = sizeof(buf);
    wind_protocol_wrap_up_gen_request_query_config(buf, len);
    GEMINAI_LOGI(TAG, "data len [%d] [%s]\n", strlen(buf), buf);
    char result[512] = {0};
    int len_result = sizeof(result);
    defcommnd_up(buf, strlen(buf), result, len_result);
    printf("result: [%s]\n", result);
}

void wind_set_config()
{
    GEMINAI_LOGI(TAG, "wind set config");
    char buf[512] = {0};
    int len = sizeof(buf);
    WindProUpdateConfig config;
    config.capture_angle = 32;
    config.door_open_angle = 3;
    config.door_open_timeout = 28;
    wind_protocol_wrap_up_gen_request_set_config(buf, len, &config);
    GEMINAI_LOGI(TAG, "data len [%d] [%s]\n", strlen(buf), buf);
    char result[512] = {0};
    int len_result = sizeof(result);
    defcommnd_up(buf, strlen(buf), result, len_result);
    printf("result: [%s]\n", result);
}

void wind_open_usbstream()
{
    GEMINAI_LOGI(TAG, "wind open usbstream\n");
    char buf[512] = {0};
    int len = sizeof(buf);
    wind_protocol_wrap_up_gen_request_usb_stream(buf, len, 1);
    GEMINAI_LOGI(TAG, "data len [%d] [%s]\n", strlen(buf), buf);
    char result[512] = {0};
    int len_result = sizeof(result);
    defcommnd_up(buf, strlen(buf), result, len_result);
    printf("result: [%s]\n", result);
}

void wind_close_usbstream()
{
    GEMINAI_LOGI(TAG, "wind close usbstream\n");
    char buf[512] = {0};
    int len = sizeof(buf);
    wind_protocol_wrap_up_gen_request_usb_stream(buf, len, 0);
    GEMINAI_LOGI(TAG, "data len [%d] [%s]\n", strlen(buf), buf);
    char result[512] = {0};
    int len_result = sizeof(result);
    defcommnd_up(buf, strlen(buf), result, len_result);
    printf("result: [%s]\n", result);
}

static void wind_modbus_run()
{
    wind_get_event();

    //    wind_set_config();
    //    vTaskDelay(3000);
    //    wind_get_config();
    //    vTaskDelay(1000);

    //        wind_open_usbstream();
}
int gpio_init_camera(int num, int on)
{
    // zero-initialize the config structure.
    gpio_config_t io_conf = {};
    // disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    // set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    // bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = 1ULL << num;
    // disable pull-down mode
    io_conf.pull_down_en = 0;
    // disable pull-up mode
    io_conf.pull_up_en = 0;
    // configure GPIO with the given settings
    gpio_config(&io_conf);
    gpio_set_level(num, on);
    return 0;
}
static void wind_connect_task(void *pvParameters)
{

    // gpio_init_camera(GPIO_NUM_14, 1);
    // gpio_init_camera(GPIO_NUM_48, 1);
    // gpio_init_camera(GPIO_NUM_21, 1);
    vTaskDelay(1000);
    wind_get_software();
    /*初始化系统事件链表*/
    systerm_event_list_init();
    while (1)
    {
        //        wind_connect_transfer();
        wind_modbus_run();
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void create_modbus_task()
{
    extern int gpio_init_camera(int num, int on);
    gpio_init_camera(GPIO_NUM_14, 1);
    gpio_init_camera(GPIO_NUM_48, 1);
    gpio_init_camera(GPIO_NUM_21, 1);
    modbus_task_start();
    xTaskCreate(wind_connect_task, "wind_connect", 1024 * 20, NULL, 5, NULL);
}